//
//  APIErrorMiddleware.swift
//  App
//
//  Created by 汤泽川 on 2019/3/26.
//

import Foundation
import Vapor

public final class APIErrorMiddleware : Middleware {
    
    
    /// See `Middleware`.
    public func respond(to req: Request, chainingTo next: Responder) throws -> Future<Response> {
        let response: Future<Response>
        do {
            response = try next.respond(to: req)
        } catch {
            response = req.eventLoop.newFailedFuture(error: error)
        }
        
        return response.catchFlatMap { error in
            if let response = error as? ResponseEncodable {
                do {
                    return try response.encode(for: req)
                } catch {
                    return req.future(self.resolveError(req, error))
                }
            } else {
                return req.future(self.resolveError(req, error))
            }
        }
    }
    
    private func resolveError(_ req : Request, _ error : Error) -> Response {
        
        // variables to determine
        let status: HTTPResponseStatus
        let reason: String
        let headers: HTTPHeaders
        let clientCode : UInt
        
        // inspect the error type
        switch error {
        case let abort as AbortError:
            // this is an abort error, we should use its status, reason, and headers
            reason = abort.reason
            status = abort.status
            headers = abort.headers
            clientCode = status.code
        case _ as ValidationError:
            // this is a validation error
            reason = "请求参数不完整，请检查参数列表"
            status = .badRequest
            headers = [:]
            clientCode = status.code
        case let apiError as APIError:
            reason = apiError.message
            status = .ok
            headers = [:]
            clientCode = UInt(apiError.status)
        default:
            // not an abort error, and not debuggable or in dev mode
            // just deliver a generic 500 to avoid exposing any sensitive error info
            reason = "服务器开小差了，请稍后再试"
            status = .internalServerError
            headers = [:]
            clientCode = status.code
        }
        print(error)
        // create a Response with appropriate status
        let res = req.response(http: .init(status: status, headers: headers))

        // attempt to serialize the error to json
        do {
            let errorResponse = APIError(status: Int(clientCode), message: reason)
            res.http.body = try HTTPBody(data: JSONEncoder().encode(errorResponse))
            res.http.headers.replaceOrAdd(name: .contentType, value: "application/json; charset=utf-8")
        } catch {
            res.http.body = HTTPBody(string: "Oops: \(error)")
            res.http.headers.replaceOrAdd(name: .contentType, value: "text/plain; charset=utf-8")
        }
        return res
    }
    
}
